﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using FreeSwitch.EventSocket.Parser;

namespace FreeSwitch.EventSocket.Events
{
	public class EventDispatcher
	{
		private readonly Dictionary<string, Type> _eventTypes = new Dictionary<string, Type>();
		private readonly ILogger _logger = LogManager.GetLogger(typeof (EventDispatcher));

		public EventDispatcher()
		{
			EventTypeLoader.ScanForEvents(GetType().Assembly, (name, type) => _eventTypes.Add(name, type));
		}

		public void Process(ParsedMessage message)
		{
			NameValueCollection collection = ParseBody(message.Body.ToString());
			if (collection == null)
				return;

			string name = string.Compare(collection["event-name"], "custom", true) == 0
			              	? collection["event-subclass"]
			              	: collection["event-name"];
			if (string.IsNullOrEmpty(name))
			{
				_logger.Warning("Invalid event message: " + message);
				return;
			}

			Type type;
			if (!_eventTypes.TryGetValue(name, out type))
			{
				_logger.Warning("Failed to find event with name: " + name);
				return;
			}

			try
			{
				var evt = (Event) Activator.CreateInstance(type);
				evt.Parse(collection);
				_logger.Debug(evt.ToString());
				EventReceived(this, new EventReceivedEventArgs(evt));
			}
			catch (Exception err)
			{
				_logger.Error("Failed to parse event: " + message, err);
			}
		}

		public void Send(Event value)
		{
			var builder = new StringBuilder();
		}

		protected NameValueCollection ParseBody(string message)
		{
			var parameters = new NameValueCollection();

			var reader = new StringReader(message);
			string line = reader.ReadLine();
			while (!string.IsNullOrEmpty(line))
			{
				int pos = line.IndexOf(":");
				if (pos == -1)
				{
					_logger.Error("Failed to parse message: ****\r\n" + message + "\r\n****, no colon at line: " + line);
					return null;
				}

				string name = line.Substring(0, pos).Trim().ToLower();
				string value = line.Substring(pos + 1).Trim();
				parameters.Add(name, Uri.UnescapeDataString(value));

				line = reader.ReadLine();
			}

			return parameters;
		}


		public event EventHandler<EventReceivedEventArgs> EventReceived = delegate { };
	}

	public class EventReceivedEventArgs : EventArgs
	{
		public EventReceivedEventArgs(Event evt)
		{
			Evt = evt;
		}

		public Event Evt { get; private set; }
	}
}